import panzoom from "panzoom";
import {
  GenNonDuplicateID
} from "@/util/until";

/* eslint-disable */
const methods = {
  init() {
    this.jsPlumb.ready(() => {
      // 导入默认配置
      this.jsPlumb.importDefaults(this.jsplumbSetting);
      //完成连线前的校验
      this.jsPlumb.bind("beforeDrop", evt => {
        let res = () => {}; //此处可以添加是否创建连接的校验， 返回 false 则不添加；
        return res;
      });
      this.jsPlumb.bind("connectionDragStop", evt => {
        this.addLine(evt);
      });
      //连线双击删除事件
      this.jsPlumb.bind("dblclick", (conn, originalEvent) => {
        this.confirmDelLine(conn);
      });
      //断开连线后，维护本地数据
      this.jsPlumb.bind("connectionDetached", evt => {
        this.deleLine(evt);
      });
      this.loadEasyFlow();
      // 会使整个jsPlumb立即重绘。
      this.jsPlumb.setSuspendDrawing(false, true);
    });
    this.initPanZoom();
  },
  // 加载流程图
  loadEasyFlow() {
    // 初始化节点
    for (let i = 0; i < this.data.nodeList.length; i++) {
      let node = this.data.nodeList[i];
      // 设置源点，可以拖出线连接其他节点
      this.jsPlumb.makeSource(node.id, this.jsplumbSourceOptions);
      // 设置目标点，其他源点拖出的线可以连接该节点
      this.jsPlumb.makeTarget(node.id, this.jsplumbTargetOptions);
      this.draggableNode(node.id);
    }
    this.updateOverlays();
  },
  updateOverlays() {
    console.log("updateOverlays");
    console.log(this.data.lineList);
    // 初始化连线
    this.jsPlumb.unbind("connection"); //取消连接事件
    for (let i = 0; i < this.data.lineList.length; i++) {
      let line = this.data.lineList[i];
      this.jsPlumb.connect({
          source: line.from,
          target: line.to,
          overlays: [
            [
              "Custom",
              {
                create: function () {
                  return $(`<div id="${line.id}"></div>`);
                },
                location: 0.5,
                cssClass: "delete-connection",
                events: {
                  click: this.handleIcoClick
                }
              }
            ]
          ]
        },
        this.jsplumbConnectOptions
      );
    }
  },
  // 连线上小图标点击事件
  handleIcoClick(labelOverlay, originalEvent) {
    const {
      component: {
        sourceId,
        targetId
      }
    } = labelOverlay;

    const {
      attributes
    } = originalEvent.srcElement;
    const {
      nodeValue
    } = attributes["id"];

    console.log("连线上小图标点击事件");
    console.log("id：" + nodeValue);
    console.log("sourceId：" + sourceId);
    console.log("targetId：" + targetId);
  },
  draggableNode(nodeId) {
    this.jsPlumb.draggable(nodeId, {
      grid: this.commonGrid,
      drag: params => {
        this.alignForLine(nodeId, params.pos);
      },
      start: () => {},
      stop: params => {
        this.auxiliaryLine.isShowXLine = false;
        this.auxiliaryLine.isShowYLine = false;
        this.changeNodePosition(nodeId, params.pos);
      }
    });
  },
  //移动节点时，动态显示对齐线
  alignForLine(nodeId, position) {
    let showXLine = false,
      showYLine = false;
    this.data.nodeList.some(el => {
      if (el.id !== nodeId && el.left == position[0] + "px") {
        this.auxiliaryLinePos.x = position[0] + 60;
        showYLine = true;
      }
      if (el.id !== nodeId && el.top == position[1] + "px") {
        this.auxiliaryLinePos.y = position[1] + 20;
        showXLine = true;
      }
    });
    this.auxiliaryLine.isShowYLine = showYLine;
    this.auxiliaryLine.isShowXLine = showXLine;
  },
  changeNodePosition(nodeId, pos) {
    this.data.nodeList.some(v => {
      if (nodeId == v.id) {
        v.left = pos[0] + "px";
        v.top = pos[1] + "px";
        return true;
      } else {
        return false;
      }
    });
  },
  // 设置元素拖拽开始事件
  drag(ele, item) {
    this.currentItem = item;
    console.log("drag");
    console.log(item);
  },
  // 当被拖动的元素在目标区域被放下时触发此事件
  drop(event) {
    console.log("drop");
    const containerRect = this.jsPlumb.getContainer().getBoundingClientRect();
    const scale = this.getScale();
    // pageX和pageY两个属性代表鼠标光标在页面中的位置，因此坐标是从页面本身而非视口的左边和顶边计算的。
    // 在没有滚动的情况下，clientX和cilentY与pageX和pageY是相等的。
    // 鼠标在盒子上的位置 = 鼠标坐标 - 盒子坐标
    let left = (event.pageX - containerRect.left - 60) / scale;
    let top = (event.pageY - containerRect.top - 20) / scale;

    var temp = {
      ...this.currentItem,
      id: GenNonDuplicateID(8),
      left: Math.round(left / 20) * 20 + "px",
      top: Math.round(top / 20) * 20 + "px"
    };
    this.addNode(temp);
  },
  addLine(line) {
    console.log("line111");
    console.log(this.jsPlumb);

    let from = line.source.id;
    let to = line.target.id;
    this.data.lineList.push({
      from,
      to,
      label: "连线名称",
      id: GenNonDuplicateID(8),
      Remark: ""
    });
    this.updateOverlays();
    console.log("Submit!");
    console.log(JSON.stringify(this.data));
  },
  confirmDelLine(line) {
    this.$confirm("确认删除该连线？", "删除连线", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
      .then(() => {
        this.jsPlumb.deleteConnection(line);
        console.log("Submit!");
        console.log(JSON.stringify(this.data));
      })
      .catch(() => {
        this.$message.info("已取消");
      });
  },
  deleLine(line) {
    this.data.lineList.forEach((item, index) => {
      if (item.from === line.sourceId && item.to === line.targetId) {
        this.data.lineList.splice(index, 1);
      }
    });
  },
  // dragover默认事件就是不触发drag事件，取消默认事件后，才会触发drag事件
  // 当被拖动的元素在目标区域内拖动时触发此事件
  allowDrop(event) {
    event.preventDefault();
  },
  getScale() {
    let scale1;
    if (this.jsPlumb.pan) {
      const {
        scale
      } = this.jsPlumb.pan.getTransform();
      scale1 = scale;
    } else {
      const matrix = window.getComputedStyle(
        this.jsPlumb.getContainer()
      ).transform;
      scale1 = matrix.split(", ")[3] * 1;
    }
    this.jsPlumb.setZoom(scale1); // 缩放倍数
    return scale1;
  },
  // 添加新的节点
  addNode(temp) {
    this.data.nodeList.push(temp);
    // this.jsPlumb.unmakeSource(temp.id);
    // this.jsPlumb.unmakeTarget(temp.id);
    this.$nextTick(() => {
      this.jsPlumb.makeSource(temp.id, this.jsplumbSourceOptions);
      this.jsPlumb.makeTarget(temp.id, this.jsplumbTargetOptions);
      this.draggableNode(temp.id);
    });
  },
  initPanZoom() {
    const mainContainer = this.jsPlumb.getContainer();
    const mainContainerWrap = mainContainer.parentNode;
    const pan = panzoom(mainContainer, {
      smoothScroll: false,
      bounds: true,
      // autocenter: true,
      zoomDoubleClickSpeed: 1,
      minZoom: 0.5,
      maxZoom: 2,
      //设置滚动缩放的组合键，默认不需要组合键
      beforeWheel: e => {
        // console.log(e)
        // let shouldIgnore = !e.ctrlKey
        // return shouldIgnore
      },
      beforeMouseDown: function (e) {
        // allow mouse-down panning only if altKey is down. Otherwise - ignore
        var shouldIgnore = e.ctrlKey;
        return shouldIgnore;
      }
    });
    this.jsPlumb.mainContainerWrap = mainContainerWrap;
    this.jsPlumb.pan = pan;
    // 缩放时设置jsPlumb的缩放比率
    pan.on("zoom", e => {
      const {
        x,
        y,
        scale
      } = e.getTransform();
      this.jsPlumb.setZoom(scale);
      //根据缩放比例，缩放对齐辅助线长度和位置
      this.auxiliaryLinePos.width = (1 / scale) * 100 + "%";
      this.auxiliaryLinePos.height = (1 / scale) * 100 + "%";
      this.auxiliaryLinePos.offsetX = -(x / scale);
      this.auxiliaryLinePos.offsetY = -(y / scale);
    });
    pan.on("panend", e => {
      const {
        x,
        y,
        scale
      } = e.getTransform();
      this.auxiliaryLinePos.width = (1 / scale) * 100 + "%";
      this.auxiliaryLinePos.height = (1 / scale) * 100 + "%";
      this.auxiliaryLinePos.offsetX = -(x / scale);
      this.auxiliaryLinePos.offsetY = -(y / scale);
    });

    // 平移时设置鼠标样式
    mainContainerWrap.style.cursor = "grab";
    mainContainerWrap.addEventListener("mousedown", function wrapMousedown() {
      this.style.cursor = "grabbing";
      mainContainerWrap.addEventListener("mouseout", function wrapMouseout() {
        this.style.cursor = "grab";
      });
    });
    mainContainerWrap.addEventListener("mouseup", function wrapMouseup() {
      this.style.cursor = "grab";
    });
  },
  setNodeName(nodeId, name) {
    this.data.nodeList.some(v => {
      if (v.id === nodeId) {
        v.nodeName = name;
        return true;
      } else {
        return false;
      }
    });
    console.log("Submit");
    console.log(JSON.stringify(this.data));
  },
  // 删除节点
  deleteNode(node) {
    console.log("删除节点");
    this.data.nodeList.some((v, index) => {
      if (v.id === node.id) {
        this.data.nodeList.splice(index, 1);
        this.jsPlumb.remove(v.id);
        console.log("Submit");
        console.log(JSON.stringify(this.data));
        return true;
      } else {
        return false;
      }
    });
  },

  //更改连线状态
  changeLineState(nodeId, val) {
    // 获取所有连接线
    let lines = this.jsPlumb.getAllConnections();
    lines.forEach(line => {
      if (line.targetId === nodeId || line.sourceId === nodeId) {
        if (val) {
          line.canvas.classList.add("active");
        } else {
          line.canvas.classList.remove("active");
        }
      }
    });
  },

  //初始化节点位置  （以便对齐,居中）
  fixNodesPosition() {
    if (this.data.nodeList && this.$refs.flowWrap) {
      // getBoundingClientRect用于获取元素相对与浏览器视口的位置
      // 由于getBoundingClientRect()已经是w3c标准，所以不用担心兼容，不过在ie下还是有所区别
      /**
       * 
        {
          top: '元素顶部相对于视口顶部的距离',
          bottom: '元素底部相对于视口顶部的距离',
          left: '元素左边相对于视口左边的距离',
          right: '元素右边相对于视口左边的距离',
          height: '元素高度',
          width: '元素宽度'
        }

        // 兼容写法
        function getClientReat(client) {
            const { top, bottom, left, right, height, width } = client.getBoundingClientRect()
            return {
                top,
                bottom,
                left,
                right,
                height: height || bottom - top,
                width:    width || right - left
            }
        }
       * 
       */
      let wrapInfo = this.$refs.flowWrap.getBoundingClientRect();
      let minLeft = wrapInfo.width,
        minTop = wrapInfo.height;
      let nodePoint = {
        left: 0,
        right: 0,
        top: 0,
        bottom: 0
      };
      this.data.nodeList.forEach(el => {
        let top = Number(el.top.substring(0, el.top.length - 2)); // 去掉单位px，转换为数字型160
        let left = Number(el.left.substring(0, el.left.length - 2)); // 100
        minLeft = left < minLeft ? left : minLeft;
        minTop = top < minTop ? top : minTop;
      });
      nodePoint.left = minLeft;
      nodePoint.top = minTop;

      this.data.nodeList.map(el => {
        let left = Number(el.left.substring(0, el.left.length - 2));
        let top = Number(el.top.substring(0, el.top.length - 2));
        el.left = Math.round(left / 20) * 20 + "px";
        el.top = Math.round(top / 20) * 20 + "px";
      });
    }
  }
};

export default methods;